package com.weilive.core.protocol.json;

import org.jboss.netty.channel.Channel;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;

import com.alibaba.fastjson.JSONObject;
import com.weilive.core.netty.http.HttpServlet;
import com.weilive.core.protocol.PacketCodec;
import com.weilive.core.session.RoleContextHolder;
import com.weilive.core.session.SessionAccount;
import com.weilive.core.utils.QueryStringDecoder;

public class JsonRequest {

	private static final String HTTP_JSON_PREFIX = "/api";

	public final Integer id;
	public final Integer codec;
	public final String type;
	public final Object data;
	public final JsonRequestHandler handler;
	public final Channel channel;

	public static JsonRequest decode(Channel channel, HttpRequest request) {
		if (request.getMethod() != HttpMethod.GET && request.getMethod() != HttpMethod.POST) {
			return null;
		}
		try {
			String uri = request.getUri();
			if (uri.startsWith(HTTP_JSON_PREFIX)) {
				return decode(channel, HttpServlet.getRequestContent(request));
			} else {
				QueryStringDecoder uriDecoder = new QueryStringDecoder(request.getUri());
				String type = uriDecoder.getPath().replace("/", "");
				// >>>>>> 特殊处理
				if (type.charAt(3) != '_') {
					type = "CSQ_" + type;
				}
				// <<<<<<
				if (type == null || JsonCodec.isHandlerForTypeImplement(type) == false) {
					return null;
				}
				Integer codec = uriDecoder.getInt("codec");
				JSONObject data;
				if (request.getMethod() == HttpMethod.GET) {
					if (codec != null && PacketCodec.clientIsGZIP(codec)) {
						data = JSONObject.parseObject(PacketCodec.decode(codec, uriDecoder.get("data")));
					} else {
						data = JSONObject.parseObject(uriDecoder.get("data"));
					}
				} else {
					if (codec != null && PacketCodec.clientIsGZIP(codec)) {
						data = JSONObject.parseObject(PacketCodec.decode(codec, HttpServlet.getRequestContent(request)));
					} else {
						data = JSONObject.parseObject(HttpServlet.getRequestContent(request));
					}
				}
				return new JsonRequest(channel, null, codec, type, data);
			}
		} catch (Exception e) {
			return null;
		}
	}
	
	
	

	public static JsonRequest decode(Channel channel, String text) throws Exception {
		JsonPacket packet = JsonPacket.decode(text);
		if (packet.type == null || JsonCodec.isHandlerForTypeImplement(packet.type) == false) {
			return null;
		}
		return new JsonRequest(channel, packet.id, packet.codec, packet.type, (JSONObject) packet.data);
	}

	private JsonRequest(Channel channel, Integer id, Integer codec, String type, JSONObject data) {
		this.channel = channel;
		this.id = id;
		this.type = type;
		this.codec = codec;
		this.handler = JsonCodec.getHandlerByType(type);
		this.data = JSONObject.toJavaObject(data, handler.getRequestType());
	}

	public JsonRequest(Object data) {
		this.channel = null;
		this.id = null;
		this.type = data.getClass().getSimpleName();
		this.codec = null;
		this.handler = JsonCodec.getHandlerByType(type);
		this.data = data;
	}

	public Integer getId() {
		return id;
	}

	public Integer getCodec() {
		return codec;
	}

	public String getType() {
		return type;
	}

	public Object getData() {
		return data;
	}

	public JsonRequestHandler getHandler() {
		return handler;
	}

	public Channel getChannel() {
		return channel;
	}

	public long getPlayerId() {
		if (channel != null) {
			SessionAccount data = (SessionAccount) channel.getAttachment();
			if (data != null) {
				// websocket
				return data.getUserId();
			} else {
				// http
				return RoleContextHolder.getRoleId();
			}
		}
		return -1;
	}

	@Override
	public String toString() {
		String id_str = id == null ? "" : String.format("\"id\":%d, ", id);
		String codec_str = codec == null ? "" : String.format("\"codec\":%d, ", codec);
		return String.format("{%s%s\"type\":\"%s\", \"data\":%s}", id_str, codec_str, type, JSONObject.toJSONString(data));
	}
}
